home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cnstrnts / skyblue.lha / SkyBlue / sky-blue.lisp < prev   
Lisp/Scheme  |  1993-07-24  |  51KB  |  1,426 lines

  1. ;;;-*- Package: :sky-blue; Syntax: Common-Lisp; Mode: Lisp -*-; 
  2.  
  3. (in-package :sky-blue :nicknames '(:sb) :use '(:lisp))
  4.  
  5. (eval-when (load eval compile) (require :loop))
  6.  
  7. (export '(
  8.       create-sb-constraint
  9.       create-sb-method
  10.       create-sb-variable
  11.       
  12.       add-set-slot-fn
  13.       remove-set-slot-fn
  14.       
  15.       get-sb-constraint-slot
  16.       set-sb-constraint-slot
  17.       get-sb-variable-slot
  18.       set-sb-variable-slot
  19.       get-sb-method-slot
  20.       get-sb-method-slot
  21.       
  22.       sb-constraint-p
  23.       sb-method-p
  24.       sb-variable-p
  25.  
  26.       get-sb-slot
  27.       set-sb-slot
  28.       sb-object-p
  29.       
  30.       cn-variables
  31.       cn-strength
  32.       cn-methods
  33.       cn-selected-method
  34.       cn-mark
  35.       
  36.       mt-code
  37.       mt-outputs
  38.       
  39.       var-value
  40.       var-constraints
  41.       var-determined-by
  42.       var-walk-strength
  43.       var-mark
  44.       var-valid
  45.       
  46.       sb-plan-p
  47.       extract-plan
  48.       sb-plan-valid
  49.       execute-plan
  50.       invalidate-plans-on-setting-method
  51.       
  52.       enforced
  53.       do-method-output-vars
  54.       do-selected-method-output-vars
  55.       do-method-input-vars
  56.       do-selected-method-input-vars
  57.       do-consuming-constraints
  58.  
  59.       method-output-vars
  60.       selected-method-output-vars
  61.       method-input-vars
  62.       selected-method-input-vars
  63.       consuming-constraints
  64.       
  65.       add-constraint
  66.       remove-constraint
  67.       *sky-blue-backtracking-warning*
  68.       *sky-blue-cycle-warning*
  69.       
  70.       *strength-keyword-list*
  71.       *strength-list*
  72.       *required-strength*
  73.       *weakest-strength*
  74.       get-strength
  75.       get-strength-keyword
  76.       weaker
  77.       ))
  78.  
  79. ;; ********************************************************************************
  80. ;;                       SkyBlue data structures
  81. ;; ********************************************************************************
  82.  
  83. ;; ***** strengths: represented as keywords *****
  84.  
  85. (defvar *strength-keyword-list*
  86.   (list :required :strong :medium :weak :s1 :s2 :s3 :s4 :s5 :s6 :s7 :weakest))
  87.  
  88. ;; transfer between strength keywords and numbers.
  89. ;; For convenience, can give either form to either fn.
  90.  
  91. (defun get-strength (strength)
  92.   (cond ((and (integerp strength)
  93.           (nth strength *strength-keyword-list*))
  94.      strength)
  95.     ((member strength *strength-keyword-list*)
  96.      (position strength *strength-keyword-list*))
  97.     (t
  98.      (error "get-strength: bad strength: ~S" strength))))
  99.  
  100. (defun get-strength-keyword (strength)
  101.   (cond ((and (integerp strength)
  102.           (nth strength *strength-keyword-list*))
  103.      (nth strength *strength-keyword-list*))
  104.     ((member strength *strength-keyword-list*)
  105.      strength)
  106.     (t
  107.      (error "get-strength-keyword: bad strength: ~S" strength))))
  108.  
  109. (defmacro weaker (s1 s2) `(> ,s1 ,s2))
  110.  
  111. (defvar *strength-list*
  112.     (loop for key in *strength-keyword-list*
  113.     collect (get-strength key)))
  114.  
  115. (defvar *required-strength* (get-strength :required))
  116. (defvar *weakest-strength* (get-strength :weakest))
  117.  
  118. ;; ***** marks *****
  119.  
  120. (defvar *mark-counter* 0)
  121.  
  122. ;; new-mark returns a new, unique mark.  new-mark will never return nil,
  123. ;; so we can use nil as a mark to "unmark" objects.
  124. (defun new-mark ()
  125.   (incf *mark-counter* 1)
  126.   *mark-counter*)
  127.  
  128. ;; ***** sky-blue object definitions *****
  129.  
  130. ;; constraint representation:
  131. ;;   
  132. ;;   field         | type      | description
  133. ;; ----------------+-----------+--------------------------------------------
  134. ;; variables       | set of    | the variables that this constraint references.
  135. ;;                 | variables |
  136. ;; strength        | strength  | this constraint's level in the constraint
  137. ;;                 |           |  hierarchy.
  138. ;; methods         | set of    | the potential methods for satisfying this
  139. ;;                 | methods   | constraint.
  140. ;; selected-method | method    | the method used to satisfy this constraint,
  141. ;;                 |           | nil if the constraint is not satisfied.
  142. ;;           |           | should only be manipulated by skyblue.
  143. ;; mark            | integer   | this constraint's mark value.
  144. ;; other-slots     | alist     | association list of other slot/value pairs
  145. ;; set-slot-fn     | fn(s)     | fn or list of fns to call before setting any slot
  146.  
  147. (defstruct (sb-Constraint
  148.         (:print-function
  149.          (lambda (cn str lvl)
  150.            (declare (ignore lvl))
  151.            (cond ((get-sb-slot cn :name)
  152.               (format str "{cn-~A}" (get-sb-slot cn :name)))
  153.              ((sb-constraint-strength cn)
  154.               (format str "{cn~A}"
  155.                   (get-strength-keyword (sb-constraint-strength cn))))
  156.              (t (format str "{cn}")))))
  157.         )
  158.   variables
  159.   strength
  160.   methods
  161.   selected-method
  162.   mark
  163.   other-slots
  164.   set-slot-fn
  165.   )
  166.  
  167. (defun get-sb-constraint-slot (obj slot)
  168.   (case slot
  169.     (:variables (sb-constraint-variables obj))
  170.     (:strength (sb-constraint-strength obj))
  171.     (:methods (sb-constraint-methods obj))
  172.     (:selected-method (sb-constraint-selected-method obj))
  173.     (:mark (sb-constraint-mark obj))
  174.     (:set-slot-fn (sb-constraint-set-slot-fn obj))
  175.     (t
  176.      (getf (sb-constraint-other-slots obj) slot nil))))
  177.  
  178. (defmacro cn-variables (cn) `(sb-constraint-variables ,cn))
  179. (defmacro cn-strength (cn) `(sb-constraint-strength ,cn))
  180. (defmacro cn-methods (cn) `(sb-constraint-methods ,cn))
  181. (defmacro cn-selected-method (cn) `(sb-constraint-selected-method ,cn))
  182. (defmacro cn-mark (cn) `(sb-constraint-mark ,cn))
  183.  
  184. ;; all slot-set forms call call-set-slot-fn
  185.  
  186. (defun set-sb-constraint-slot (cn slot val)
  187.   (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn slot val)
  188.   (case slot
  189.     (:variables (setf (sb-constraint-variables cn) val))
  190.     (:strength (setf (sb-constraint-strength cn) val))
  191.     (:methods (setf (sb-constraint-methods cn) val))
  192.     (:selected-method (setf (sb-constraint-selected-method cn) val))
  193.     (:mark (setf (sb-constraint-mark cn) val))
  194.     (:set-slot-fn (setf (sb-constraint-set-slot-fn cn) val))
  195.     (t
  196.      (setf (getf (sb-constraint-other-slots cn) slot nil) val)))
  197.   val)
  198.  
  199. (defsetf cn-strength (cn) (val)
  200.   `(let ((cn ,cn)(val ,val))
  201.      (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn :strength val)
  202.      (setf (sb-constraint-strength cn) val)))
  203. (defsetf cn-variables (cn) (val)
  204.   `(let ((cn ,cn)(val ,val))
  205.      (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn :variables val)
  206.      (setf (sb-constraint-variables cn) val)))
  207. (defsetf cn-methods (cn) (val)
  208.   `(let ((cn ,cn)(val ,val))
  209.      (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn :methods val)
  210.      (setf (sb-constraint-methods cn) val)))
  211. (defsetf cn-selected-method (cn) (val)
  212.   `(let ((cn ,cn)(val ,val))
  213.      (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn :selected-method val)
  214.      (setf (sb-constraint-selected-method cn) val)))
  215. (defsetf cn-mark (cn) (val)
  216.   `(let ((cn ,cn)(val ,val))
  217.      (call-set-slot-fn (sb-constraint-set-slot-fn cn) cn :mark val)
  218.      (setf (sb-constraint-mark cn) val)))
  219.  
  220. (defun create-sb-constraint (&key (name nil)
  221.                                (variables nil)
  222.                                (strength :required)
  223.                                (methods nil)
  224.                                (selected-method nil)
  225.                                (mark nil)
  226.                    (set-slot-fn nil)
  227.                                )
  228.   (let ((cn (make-sb-constraint :strength (get-strength strength)
  229.                                 :methods methods
  230.                                 :variables variables
  231.                                 :selected-method selected-method
  232.                                 :mark mark
  233.                 :set-slot-fn set-slot-fn
  234.                                 :other-slots nil)))
  235.     (when name (set-sb-slot cn :name name))
  236.     cn))
  237.  
  238. ;; methods:
  239. ;;   a method represents one possible procedure for satisfying a constraint.
  240. ;;   fields of a method representation are initialized at the constraint
  241. ;;   creation time and never modified.
  242. ;;
  243. ;;   field        | type      | description
  244. ;;   -------------+-----------+--------------------------------------------
  245. ;;   code         | procedure | the procedure to be called to execute this
  246. ;;                |           | method (passed the constraint whose selected
  247. ;;                |           | method this is).
  248. ;;   outputs      | list of vars | list of output vars for this method.
  249. ;; other-slots    | alist     | association list of other slot/value pairs
  250. ;;   set-slot-fn  |  fn(s)    | fn or list of fns to call before setting any slot
  251.  
  252. (defstruct (sb-Method
  253.         (:print-function
  254.          (lambda (mt str lvl)
  255.            (declare (ignore lvl))
  256.            (cond ((get-sb-slot mt :name)
  257.               (format str "{mt-~A}" (get-sb-slot mt :name)))
  258.              (t (format str "{mt}")))))
  259.         )
  260.   code
  261.   outputs
  262.   other-slots
  263.   set-slot-fn
  264.   )
  265.  
  266. (defun get-sb-method-slot (mt slot)
  267.   (case slot
  268.     (:code (sb-method-code mt))
  269.     (:outputs (sb-method-outputs mt))
  270.     (:set-slot-fn (sb-method-set-slot-fn mt))
  271.     (t
  272.      (getf (sb-method-other-slots mt) slot nil))))
  273.  
  274. (defmacro mt-code (mt) `(sb-method-code ,mt))
  275. (defmacro mt-outputs (mt) `(sb-method-outputs ,mt))
  276.  
  277. (defun set-sb-method-slot (mt slot val)
  278.   (call-set-slot-fn (sb-method-set-slot-fn mt) mt slot val)
  279.   (case slot
  280.     (:code (setf (sb-method-code mt) val))
  281.     (:outputs (setf (sb-method-outputs mt) val))
  282.     (:set-slot-fn (setf (sb-method-set-slot-fn mt) val))
  283.     (t
  284.      (setf (getf (sb-method-other-slots mt) slot nil) val))))
  285.  
  286. (defsetf mt-code (mt) (val)
  287.   `(let ((mt ,mt)(val ,val))
  288.      (call-set-slot-fn (sb-method-set-slot-fn mt) mt :code val)
  289.      (setf (sb-method-code mt) val)))
  290. (defsetf mt-outputs (mt) (val)
  291.   `(let ((mt ,mt)(val ,val))
  292.      (call-set-slot-fn (sb-method-set-slot-fn mt) mt :outputs val)
  293.      (setf (sb-method-outputs mt) val)))
  294.  
  295. (defun create-sb-method (&key (name nil)
  296.                   (code #'(lambda (cn) cn))
  297.                   (outputs nil))
  298.   (let ((mt (make-sb-method :code code
  299.                 :outputs outputs
  300.                 :other-slots nil)))
  301.     (when name (set-sb-slot mt :name name))
  302.     mt))
  303.  
  304. ;; variables:
  305. ;;
  306. ;;   field        | type        | description
  307. ;;  --------------+-------------+--------------------------------------------
  308. ;;  value         | any         | value of the variable
  309. ;;  constraints   | set of      | all the constraints that reference this
  310. ;;                | constraints | variable.
  311. ;;  determined-by | constraint  | the constraint that determines this
  312. ;;                |             | variable's value.
  313. ;;  walk-strength | strength    | the walkabout strength of this variable.
  314. ;;  mark          | integer     | this variable's mark value.
  315. ;;  valid         | boolean     | true if this variable value is valid
  316. ;; other-slots    | alist       | association list of other slot/value pairs
  317. ;; set-slot-fn    | fn(s)       | fn or list of fns to call before setting any slot
  318.  
  319. (defstruct (sb-Variable
  320.         (:print-function
  321.          (lambda (var str lvl)
  322.            (declare (ignore lvl))
  323.            (cond ((get-sb-slot var :name)
  324.               (format str "{var-~A}" (get-sb-slot var :name)))
  325.              (t (format str "{var}")))))
  326.         )
  327.   constraints
  328.   determined-by
  329.   walk-strength
  330.   mark
  331.   valid
  332.   value
  333.   other-slots
  334.   set-slot-fn
  335.   )
  336.  
  337. (defun get-sb-variable-slot (var slot)
  338.   (case slot
  339.     (:value (sb-variable-value var))
  340.     (:constraints (sb-variable-constraints var))
  341.     (:determined-by (sb-variable-determined-by var))
  342.     (:walk-strength (sb-variable-walk-strength var))
  343.     (:mark (sb-variable-mark var))
  344.     (:valid (sb-variable-valid var))
  345.     (:set-slot-fn (sb-variable-set-slot-fn var))
  346.     (t
  347.      (getf (sb-variable-other-slots var) slot nil))))
  348.  
  349. (defmacro var-value (var) `(sb-variable-value ,var))
  350. (defmacro var-constraints (var) `(sb-variable-constraints ,var))
  351. (defmacro var-determined-by (var) `(sb-variable-determined-by ,var))
  352. (defmacro var-walk-strength (var) `(sb-variable-walk-strength ,var))
  353. (defmacro var-mark (var) `(sb-variable-mark ,var))
  354. (defmacro var-valid (var) `(sb-variable-valid ,var))
  355.  
  356. (defun set-sb-variable-slot (var slot val)
  357.   (call-set-slot-fn (sb-variable-set-slot-fn var) var slot val)
  358.   (case slot
  359.     (:value (setf (sb-variable-value var) val))
  360.     (:constraints (setf (sb-variable-constraints var) val))
  361.     (:determined-by (setf (sb-variable-determined-by var) val))
  362.     (:walk-strength (setf (sb-variable-walk-strength var) val))
  363.     (:mark (setf (sb-variable-mark var) val))
  364.     (:valid (setf (sb-variable-valid var) val))
  365.     (:set-slot-fn (setf (sb-variable-set-slot-fn var) val))
  366.     (t
  367.      (setf (getf (sb-variable-other-slots var) slot nil) val))))
  368.  
  369. (defsetf var-value (var) (val) `(set-sb-variable-slot ,var :value ,val))
  370. (defsetf var-constraints (var) (val) `(set-sb-variable-slot ,var :constraints ,val))
  371. (defsetf var-determined-by (var) (val) `(set-sb-variable-slot ,var :determined-by ,val))
  372. (defsetf var-walk-strength (var) (val) `(set-sb-variable-slot ,var :walk-strength ,val))
  373. (defsetf var-mark (var) (val) `(set-sb-variable-slot ,var :mark ,val))
  374. (defsetf var-valid (var) (val) `(set-sb-variable-slot ,var :valid ,val))
  375.  
  376. (defun create-sb-variable (&key (name nil)
  377.                 (value nil)
  378.                 (constraints nil)
  379.                 (determined-by nil)
  380.                 (walk-strength :weakest)
  381.                 (mark 0)
  382.                 (valid t)
  383.                 (set-slot-fn nil)
  384.                 )
  385.   (let ((var (make-sb-variable :value value
  386.                    :constraints constraints
  387.                    :determined-by determined-by
  388.                    :walk-strength (get-strength walk-strength)
  389.                    :mark mark
  390.                    :valid valid
  391.                    :set-slot-fn set-slot-fn
  392.                    :other-slots nil)))
  393.     (when name (set-sb-slot var :name name))
  394.     var))
  395.  
  396. ;; ***** generic sb object fns *****
  397.  
  398. (defun get-sb-slot (obj slot)
  399.   (etypecase obj
  400.     (sb-constraint (get-sb-constraint-slot obj slot))
  401.     (sb-variable (get-sb-variable-slot obj slot))
  402.     (sb-method (get-sb-method-slot obj slot))))
  403.  
  404. (defun set-sb-slot (obj slot val)
  405.   (etypecase obj
  406.     (sb-constraint (set-sb-constraint-slot obj slot val))
  407.     (sb-variable (set-sb-variable-slot obj slot val))
  408.     (sb-method (set-sb-method-slot obj slot val))))
  409.  
  410. (defun sb-object-p (obj)
  411.   (or (sb-constraint-p obj)
  412.       (sb-variable-p obj)
  413.       (sb-method-p obj)))
  414.  
  415. ;; ***** set-slot-fn handling *****
  416.  
  417. (defun call-set-slot-fn (fns obj slot val)
  418.   (cond ((null fns)
  419.      nil)
  420.     ((listp fns)
  421.      (loop for fn in fns do (call-set-slot-fn fn obj slot val)))
  422.     (t
  423.      (funcall fns obj slot val))))
  424.  
  425. (defun add-set-slot-fn (obj fn)
  426.   (let* ((curr (get-sb-slot obj :set-slot-fn))
  427.      (curr-list (if (listp curr) curr (list curr))))
  428.     (unless (member fn curr-list)
  429.       (set-sb-slot obj :set-slot-fn (cons fn curr)))
  430.     ))
  431.  
  432. (defun remove-set-slot-fn (obj fn)
  433.   (let* ((curr (get-sb-slot obj :set-slot-fn))
  434.      (curr-list (if (listp curr) curr (list curr))))
  435.     (set-sb-slot obj :set-slot-fn (remove fn curr-list))
  436.     ))
  437.  
  438. ;; useful macros
  439.  
  440. (defmacro enforced (c)
  441.   `(cn-selected-method ,c))
  442.  
  443. (defmacro do-method-output-vars ((var-var cn-form mt-form) . body)
  444.   (declare (ignore cn-form))
  445.   `(loop for ,var-var in (MT-outputs ,mt-form) do
  446.      (progn ,@body)))
  447.  
  448. (defmacro do-selected-method-output-vars ((var-var cn-form) . body)
  449.   `(loop for ,var-var in (MT-outputs (cn-selected-method ,cn-form))
  450.        do (progn ,@body)))
  451.  
  452. (defmacro do-method-input-vars ((var-var cn-form mt-form) . body)
  453.   (let ((cn-var (gentemp))
  454.     (mt-var (gentemp))
  455.     (outputs-var (gentemp)))
  456.     `(let* ((,cn-var ,cn-form)
  457.         (,mt-var ,mt-form)
  458.         (,outputs-var (mt-outputs ,mt-var)))
  459.        (loop for ,var-var in (cn-variables ,cn-var)
  460.        do (when (not (member ,var-var ,outputs-var))
  461.         ,@body)))
  462.     ))
  463.  
  464. (defmacro do-selected-method-input-vars ((var-var cn-form) . body)
  465.   (let ((cn-var (gentemp))
  466.     (mt-var (gentemp)))    
  467.     `(let* ((,cn-var ,cn-form)
  468.         (,mt-var (cn-selected-method ,cn-var)))
  469.        (do-method-input-vars (,var-var ,cn-var ,mt-var) ,@body))
  470.     ))
  471.  
  472. (defmacro do-consuming-constraints ((constraint-var var-form) . body)
  473.   (let ((var-var (gentemp))
  474.     (var-determined-by-var (gentemp)))
  475.     `(let* ((,var-var ,var-form)
  476.         (,var-determined-by-var (var-determined-by ,var-var)))
  477.        (loop for ,constraint-var in (var-constraints ,var-form)
  478.        do (when (and (not (eq ,constraint-var ,var-determined-by-var))
  479.              (enforced ,constraint-var))
  480.         ,@body)))
  481.     ))
  482.  
  483. ;; inefficient fns for consing up lists of input, output vars
  484. ;; use methods above for efficiency
  485.  
  486. (defun method-output-vars (cn mt)
  487.   (declare (ignore cn))
  488.   (mt-outputs mt))
  489.  
  490. (defun selected-method-output-vars (cn)
  491.   (MT-outputs (cn-selected-method cn)))
  492.  
  493. (defun method-input-vars (cn mt)
  494.   (loop for var in (cn-variables cn)
  495.       when (not (member var (mt-outputs mt)))
  496.       collect var))
  497.  
  498. (defun selected-method-input-vars (cn)
  499.   (method-input-vars cn (cn-selected-method cn)))
  500.  
  501. (defun consuming-constraints (v)
  502.   (loop for cn in (var-constraints v)
  503.         when (and (enforced cn)
  504.                   (not (eql cn (var-determined-by v))))
  505.         collect cn))
  506.  
  507.  
  508. ;; ***** stack objects *****
  509.  
  510. (defstruct (sb-stack
  511.         (:conc-name "SB-STACK-")
  512.         (:print-function
  513.          (lambda (stack str lvl)
  514.            (declare (ignore lvl))
  515.            (sb-stack-print stack str)))
  516.         )
  517.   size
  518.   vector
  519.   max-vector-size
  520.   overflow)
  521.  
  522. (defun sb-stack-create (max-vector-size)
  523.   (make-sb-stack :max-vector-size max-vector-size
  524.          :vector (make-array (list max-vector-size))
  525.          :size 0
  526.          :overflow nil))
  527.  
  528. (defun sb-stack-clear (stack)
  529.   (setf (sb-stack-size stack) 0)
  530.   stack)
  531.  
  532. (defun sb-stack-push (stack elt)
  533.   (cond ((< (sb-stack-size stack) (sb-stack-max-vector-size stack))
  534.      (setf (aref (sb-stack-vector stack) (sb-stack-size stack)) elt))
  535.     (t
  536.      (push elt (sb-stack-overflow stack))))
  537.   (incf (sb-stack-size stack) 1)
  538.   elt)
  539.  
  540. (defun sb-stack-pop (stack)
  541.   (incf (sb-stack-size stack) -1)
  542.   (cond ((< (sb-stack-size stack) 0)
  543.      (cerror "return nil" "sb-stack-pop: stack empty")
  544.      (setf (sb-stack-size stack) 0)
  545.      nil)
  546.     ((< (sb-stack-size stack) (sb-stack-max-vector-size stack))
  547.      (aref (sb-stack-vector stack) (sb-stack-size stack)))
  548.     (t
  549.      (pop (sb-stack-overflow stack)))))
  550.  
  551. (defun sb-stack-empty (stack)
  552.   (zerop (sb-stack-size stack)))
  553.  
  554. ;; loops over all elts in the stack, without removing any.
  555. (defmacro do-sb-stack-elts ((var-var stack-form) . body)
  556.   (let ((stack-var (gentemp))
  557.     (vector-var (gentemp))
  558.     (elt-var (gentemp))
  559.     (overflow-var (gentemp))
  560.     (vector-size-var (gentemp)))
  561.     `(let* ((,stack-var ,stack-form)
  562.         (,vector-var (sb-stack-vector ,stack-var))
  563.         (,overflow-var (sb-stack-overflow ,stack-var))
  564.         (,vector-size-var (sb-stack-max-vector-size ,stack-var)))
  565.        (loop for ,elt-var from (1- (sb-stack-size ,stack-var)) downto 0 do
  566.          (let ((,var-var (cond ((< ,elt-var ,vector-size-var)
  567.                     (aref ,vector-var ,elt-var))
  568.                    (t (pop ,overflow-var)))))
  569.            ,@body)))
  570.     ))
  571.  
  572. (defun sb-stack-member (stack obj)
  573.   (do-sb-stack-elts (elt stack)
  574.     (when (eql elt obj)
  575.       (return-from sb-stack-member t)))
  576.   nil)
  577.  
  578. (defun sb-stack-print (stack str)
  579.   (format str "{stack(~S):" (sb-stack-size stack))
  580.   (do-sb-stack-elts (elt stack) (format str " ~S" elt))
  581.   (format str "}"))
  582.  
  583. ;; ***** stack of cns sorted by strength *****
  584.  
  585. (defstruct (sb-cns-set
  586.         (:conc-name "SB-CNS-SET-")
  587.         (:print-function
  588.          (lambda (stack str lvl)
  589.            (declare (ignore lvl))
  590.            (sb-cns-set-print stack str)))
  591.         )
  592.   size
  593.   num-strengths
  594.   cns-stacks)
  595.  
  596. (defun sb-cns-set-create (max-cns)
  597.   (let* ((num-strengths (length *strength-list*))
  598.      (cns-per-strength (truncate max-cns num-strengths))
  599.      (strength-cns-stacks (make-array (list num-strengths))))
  600.     (loop for index from 0 to (1- num-strengths) do
  601.       (setf (aref strength-cns-stacks index)
  602.         (sb-stack-create cns-per-strength)))
  603.     (make-sb-cns-set :size 0
  604.              :cns-stacks strength-cns-stacks
  605.              :num-strengths num-strengths)
  606.     ))
  607.  
  608. (defun sb-cns-set-clear (stack)
  609.   (let ((stacks (sb-cns-set-cns-stacks stack)))
  610.     (loop for index from 0 to (1- (sb-cns-set-num-strengths stack))
  611.     do (sb-stack-clear (aref stacks index)))
  612.     (setf (sb-cns-set-size stack) 0)
  613.     stack))
  614.  
  615. (defun sb-cns-set-add (stack cn)
  616.   (let* ((stacks (sb-cns-set-cns-stacks stack))
  617.      (cn-stack (aref stacks (CN-strength cn))))
  618.     (unless (sb-stack-member cn-stack cn)
  619.       (sb-stack-push cn-stack cn)
  620.       (incf (sb-cns-set-size stack) 1))
  621.     cn))
  622.  
  623. (defun sb-cns-set-pop-strongest (stack)
  624.   (incf (sb-cns-set-size stack) -1)
  625.   (cond ((< (sb-stack-size stack) 0)
  626.      (cerror "return nil" "sb-cns-set-pop: stack empty")
  627.      (sb-cns-set-clear stack)
  628.      nil)
  629.     (t
  630.      (let ((stacks (sb-cns-set-cns-stacks stack)))
  631.        (loop for index from 0 to (1- (sb-cns-set-num-strengths stack))
  632.            do (let ((cn-stack (aref stacks index)))
  633.             (when (not (sb-stack-empty cn-stack))
  634.               (return (sb-stack-pop cn-stack))))
  635.            finally (cerror "return nil" "sb-cns-set-pop: all substacks empty")))
  636.      )))
  637.  
  638. (defun sb-cns-set-empty (stack)
  639.   (zerop (sb-cns-set-size stack)))
  640.  
  641. (defun sb-cns-set-print (stack str)
  642.   (format str "{cns-set(~S):" (sb-cns-set-size stack))
  643.   (let ((stacks (sb-cns-set-cns-stacks stack)))
  644.     (loop for index from 0 to (1- (sb-cns-set-num-strengths stack))
  645.     do (let ((cn-stack (aref stacks index)))
  646.          (when (not (sb-stack-empty cn-stack))
  647.            (format str " {")
  648.            (do-sb-stack-elts (elt cn-stack) (format str "~S " elt))
  649.            (format str "}")))))
  650.   (format str "}"))
  651.  
  652.  
  653. ;; loops over all elts in the set, from strongest-to-weakest,
  654. ;; without removing any.
  655. (defmacro do-sb-cns-set-elts ((var-var set-form) . body)
  656.   (let ((set-var (gentemp))
  657.     (stacks-var (gentemp))
  658.     (index-var (gentemp))
  659.     (cn-stack-var (gentemp)))
  660.     `(let* ((,set-var ,set-form)
  661.         (,stacks-var (sb-cns-set-cns-stacks ,set-var)))
  662.        (loop for ,index-var from 0 to (1- (sb-cns-set-num-strengths ,set-var))
  663.        do (let ((,cn-stack-var (aref ,stacks-var ,index-var)))
  664.         (when (not (sb-stack-empty ,cn-stack-var))
  665.           (do-sb-stack-elts (,var-var ,cn-stack-var) ,@body)))))
  666.     ))
  667.  
  668. ;; ***** plans *****
  669.  
  670. (defstruct (sb-plan
  671.         (:conc-name "SB-PLAN-")
  672.         (:print-function
  673.          (lambda (plan str lvl)
  674.            (declare (ignore lvl))
  675.            (sb-plan-print plan str)))
  676.         )
  677.   good-cns
  678.   bad-cns
  679.   root-cns
  680.   valid
  681.   )
  682.  
  683. (defun sb-plan-print (plan str)
  684.   (format str "{~Aplan:~Sgood,~Sbad,~Sroot}"
  685.       (if (sb-plan-valid plan) "valid-" "invalid-")
  686.       (length (sb-plan-good-cns plan))
  687.       (length (sb-plan-bad-cns plan))
  688.       (length (sb-plan-root-cns plan))))
  689.  
  690. ;; ***** interlock to prevent accidental recursive calls to skyblue *****
  691. ;; add-constraint and remove-constraint should never be called recursively
  692. ;; (for example: from within a constraint method).  This signals a
  693. ;; continuable error if this is done.
  694.  
  695. (defvar *sky-blue-running* nil)
  696.  
  697. (defmacro with-sky-blue-recursion-check (&rest forms)
  698.   `(cond (*sky-blue-running*
  699.       (cerror "add-constraint or remove-constraint ignored"
  700.           "sky-blue add-constraint or remove-constraint called recursively!")
  701.       )
  702.      (t
  703.       (unwind-protect
  704.           (progn
  705.         (setq *sky-blue-running* t)
  706.         (progn ,@forms))
  707.         (setq *sky-blue-running* nil))
  708.       )))
  709.  
  710. ;; ********************************************************************************
  711. ;;                       SkyBlue algorithm
  712. ;; ********************************************************************************
  713.  
  714. ;; Sky-Blue global stacks: rather than passing these stacks between the
  715. ;; different functions, these are saved as global variables.
  716.  
  717. ;; stack of unenforced cns that we want to try enforcing, sorted by
  718. ;; strength from strongest to weakest
  719. (defvar *unenforced-cns-stack* (sb-cns-set-create 200))
  720.  
  721. ;; stack of redetermined variables that we will trace downstream from to
  722. ;; find unenforced cns.
  723. (defvar *redetermined-vars-stack* (sb-stack-create 100))
  724.  
  725. ;; stack of newly-undetermined vars and newly-added cns.  To enforce the
  726. ;; cns in the current method graph, we will trace downstream from these
  727. ;; vars and cns, evaling methods.
  728. (defvar *exec-roots-stack* (sb-stack-create 100))
  729.  
  730. ;; ***** Sky-Blue Entry Points *****
  731.  
  732. (defun add-constraint (cn)
  733.   (with-sky-blue-recursion-check
  734.       ;; clear stacks
  735.       (sb-cns-set-clear *unenforced-cns-stack*)
  736.     (sb-stack-clear *exec-roots-stack*)
  737.     ;; initialize constraint fields, and register with variables
  738.     (setf (CN-selected-method cn) nil)
  739.     (setf (CN-mark cn) nil)
  740.     (loop for v in (CN-variables cn) do
  741.       (push cn (VAR-constraints v)))
  742.     ;; find the method graph to enforce the new cn (if possible),
  743.     ;; collecting any exec-roots.
  744.     (sb-cns-set-add *unenforced-cns-stack* cn)
  745.     (update-method-graph)
  746.     ;; enforce method graph cns by evaluating cn methods.
  747.     (exec-from-roots)
  748.     )
  749.   cn)
  750.  
  751. (defun remove-constraint (cn)
  752.   (with-sky-blue-recursion-check
  753.       ;; unregister cn from variables
  754.       (loop for v in (CN-variables cn) do
  755.         (setf (VAR-constraints v)
  756.               (remove cn (VAR-constraints v))))
  757.     (when (enforced cn)
  758.       ;; clear stacks
  759.       (sb-cns-set-clear *unenforced-cns-stack*)
  760.       (sb-stack-clear *redetermined-vars-stack*)
  761.       (sb-stack-clear *exec-roots-stack*)
  762.       ;; loop over current outputs of cn
  763.       (do-selected-method-output-vars (var cn)
  764.     ;; un-determine current method's output vars
  765.     (setf (VAR-determined-by var) nil)
  766.     (setf (VAR-walk-strength var) *weakest-strength*)
  767.     ;; collect output vars on redetermined vars stack
  768.     (sb-stack-push *redetermined-vars-stack* var)
  769.     ;; also collect output vars as possible exec roots
  770.     (sb-stack-push *exec-roots-stack* var)
  771.     )
  772.       ;; un-enforce cn
  773.       (setf (CN-selected-method cn) nil)
  774.       ;; propagate walkstrength from newly undetermined vars
  775.       (propagate-walkstrength *redetermined-vars-stack*)
  776.       ;; collect all unenforced cns downstream of undetermined vars
  777.       ;; that have the same or weaker strength than the removed cn
  778.       (collect-unenforced (CN-strength cn) t)
  779.       ;; find method graph to enforce the collected unenforced cns
  780.       (update-method-graph)
  781.       ;; enforce method graph cns by evaluating cn methods.
  782.       (exec-from-roots)
  783.       )
  784.     )
  785.     cn)
  786.  
  787. ;; update-method-graph modifies the current method graph to include the
  788. ;; constraints in *unenforced-cns-stack*, maintaining it as a
  789. ;; locally-graph-better method graph.  Each time a cn is enforced, other
  790. ;; unenforced cns that might be enforcable may be found, so these are added
  791. ;; to the stack.  As a heuristic, the stack is kept in order of cn
  792. ;; strength, and we always try enforcing the strongest unenforced cn first.
  793. ;; This fn also updates *exec-roots-stack* by adding any cns were
  794. ;; sucessfully enforced, as well as any newly-undetermined vars that should
  795. ;; now be validated.  *redetermined-vars-stack* is a stack that is used for
  796. ;; temporary storage of a list of undetermined variables.
  797. (defun update-method-graph ()
  798.   (let* (ok cn)
  799.     (loop until (sb-cns-set-empty *unenforced-cns-stack*) do
  800.       (setq cn (sb-cns-set-pop-strongest *unenforced-cns-stack*))
  801.       ;; try building mvine, collecting newly-undetermined vars
  802.       (sb-stack-clear *redetermined-vars-stack*)
  803.       (setq ok (build-mvine cn))
  804.       (when ok
  805.         ;; we found an mvine!
  806.         ;; prop walkstrengths down mvine, and from newly undetermined vars
  807.         (propagate-walkstrength (list cn *redetermined-vars-stack*))
  808.         ;; collect any cns strictly weaker than cn that may now be enforcible
  809.         (collect-unenforced (CN-strength cn) nil)
  810.         ;; add all new undetermined vars and newly-added cn to exec-roots
  811.         (do-sb-stack-elts (var *redetermined-vars-stack*)
  812.           (when (null (VAR-determined-by var))
  813.         (sb-stack-push *exec-roots-stack* var)))
  814.         (sb-stack-push *exec-roots-stack* cn)
  815.         ))
  816.     ))
  817.  
  818. ;; ***** building method vines *****
  819.  
  820. ;; build-mvine is one of a set of mutually-recursive fns that perform a
  821. ;; backtracking search for a mutually-consistant method assignments for the
  822. ;; specified constraint.  The "mvine" that is being built is a method
  823. ;; vine rooted at the cn originially used to start this process, which had
  824. ;; strength root-strength.  The leaves of the mvine are cns weaker than
  825. ;; this strength, that are left unenforced (with no method selected).  It
  826. ;; is also possible that a leaf may loop back to a lower part of the mvine:
  827. ;; this is acceptable.  These functions perform the search by marking cns
  828. ;; and vars with the specified mark: only when a complete mvine is found
  829. ;; are the selected methods changed to reflect this.  These functions all
  830. ;; return t iff a way was found to enforce the cn, nil otherwise.  All of
  831. ;; the functions add redetermined vars to the stack
  832. ;; *redetermined-vars-stack*.
  833.  
  834. (defvar *mvine-cns-stack* (sb-stack-create 30))
  835.  
  836. (defun build-mvine (cn)
  837.   (sb-stack-clear *mvine-cns-stack*)
  838.   ;; try to build mvine starting with enforcing root cn as a branch
  839.   (mvine-enforce-cn cn (cn-strength cn) (new-mark)))
  840.  
  841. (defun mvine-grow (root-strength done-mark)
  842.   (if (sb-stack-empty *mvine-cns-stack*)
  843.       ;; no more cns, we have found a complete prop path!
  844.       t
  845.     ;; process next cn
  846.     (let* (cn ok)
  847.       (setq cn (sb-stack-pop *mvine-cns-stack*))
  848.       (cond ((eql done-mark (CN-mark cn))
  849.          ;; this cn has already been marked: process other cns
  850.          (setq ok (mvine-grow root-strength done-mark)))
  851.         ((weaker (CN-strength cn) root-strength)
  852.          ;; this cn is weaker than the root cn: revoke it
  853.          (setq ok (mvine-revoke-cn cn root-strength done-mark)))
  854.         (t
  855.          ;; try to find a method for this cn
  856.          (setq ok (mvine-enforce-cn cn root-strength done-mark)))
  857.         )
  858.       ;; if we are backtracking, must restore *mvine-cns-stack*
  859.       (when (not ok)
  860.     (sb-stack-push *mvine-cns-stack* cn))
  861.       ok)
  862.     ))
  863.  
  864. (defun mvine-revoke-cn (cn root-strength done-mark)
  865.   (let* ((old-mt (CN-selected-method cn))
  866.      ok)
  867.     ;; mark this cn.  we will process it by revoking it.
  868.     (setf (CN-mark cn) done-mark)
  869.     ;; try building rest of mvine
  870.     (setq ok (mvine-grow root-strength done-mark))
  871.     (cond (ok
  872.        ;; we found entire mvine!
  873.        ;; undetermine unmarked old-mt outputs,
  874.        ;; and save on *redetermined-vars-stack*
  875.        (loop for var in (MT-outputs old-mt)
  876.            when (not (eql done-mark (VAR-mark var))) do
  877.          ;; unmarked vars must be newly undetermined.
  878.          ;; reset determined-by and walkstrength of newly undetermined vars
  879.          (setf (VAR-determined-by var) nil)
  880.          (setf (VAR-walk-strength var) *weakest-strength*)
  881.          (sb-stack-push *redetermined-vars-stack* var)
  882.          )
  883.        ;; set selected-method for this cn
  884.        (setf (CN-selected-method cn) nil)
  885.        t)
  886.       (t
  887.        ;; no mvine found: we are backtracking.
  888.        ;; there is no other choice for this cn, so just un-mark cn
  889.        ;; and continue backtracking.
  890.        (setf (CN-mark cn) nil)
  891.        nil))
  892.     ))
  893.  
  894. (defun mvine-enforce-cn (cn root-strength done-mark)
  895.   (let* ((old-mt (CN-selected-method cn))
  896.      ;; note: old-mt=nil if cn is the unenforced mvine root
  897.      (old-outputs (if old-mt (MT-outputs old-mt) nil))
  898.      ok)
  899.     ;; mark this constraint: we will try to make it into a branch
  900.     (setf (CN-mark cn) done-mark)
  901.     ;; try each possible method: returning if one is found that allows
  902.     ;; mvine to be built
  903.     (loop for mt in (CN-methods cn)
  904.     when (possible-method mt root-strength done-mark old-outputs)
  905.     do
  906.       (let* ((next-cns-cnt 0))
  907.         ;; add constraints determining this mt's outputs onto stack
  908.         ;; (and count them so we know how many to pop during backtracking)
  909.         (loop for var in (MT-outputs mt) do
  910.           (let ((next-cn (VAR-determined-by var)))
  911.             (when (and next-cn (not (eql cn next-cn)))
  912.               (sb-stack-push *mvine-cns-stack* next-cn)
  913.               (setq next-cns-cnt (+ next-cns-cnt 1)))))
  914.         ;; let's try to build the mvine with this cn/mt.
  915.         ;; mark the output vars of the method
  916.         (loop for var in (MT-outputs mt) do
  917.           (setf (VAR-mark var) done-mark))
  918.         ;; try building rest of mvine
  919.         (setq ok (mvine-grow root-strength done-mark))
  920.         (cond (ok
  921.            ;; we found entire mvine!
  922.            ;; undetermine unmarked output vars of old mt,
  923.            ;; and save on *redetermined-vars-stack*
  924.            (loop for var in old-outputs
  925.                when (not (eql done-mark (VAR-mark var))) do
  926.              ;; unmarked vars must be newly undetermined.
  927.              ;; reset determined-by and walkstrength of newly undetermined vars
  928.              (setf (VAR-determined-by var) nil)
  929.              (setf (VAR-walk-strength var) *weakest-strength*)
  930.              (sb-stack-push *redetermined-vars-stack* var)
  931.              )
  932.            ;; set selected method for this cn, and ptrs in new outputs
  933.            ;; and save on *redetermined-vars-stack*
  934.            (setf (CN-selected-method cn) mt)
  935.            (loop for var in (MT-outputs mt) do
  936.              (setf (VAR-determined-by var) cn)
  937.              (sb-stack-push *redetermined-vars-stack* var)
  938.              )
  939.            ;; return t without trying any more methods
  940.            (return-from mvine-enforce-cn t))
  941.           (t
  942.            ;; no mvine found: try next method
  943.            ;; "undo" current method choice: unmark method outputs
  944.            (loop for var in (MT-outputs mt) do
  945.              (setf (VAR-mark var) nil))
  946.            ;; pop constraints we added above
  947.            (loop for cnt from 1 to next-cns-cnt do
  948.              (sb-stack-pop *mvine-cns-stack*))
  949.            ))
  950.         ;; unless we found a soln: continue loop to try next method
  951.         ))
  952.     ;; loop finished: no more methods to try: unmark cn and backtrack
  953.     (setf (CN-mark cn) nil)
  954.     ;; signal backtracking point (unless this is root cn)
  955.     (unless (null old-mt)
  956.       (signal-backtracking cn))
  957.     nil))
  958.  
  959. (defvar *sky-blue-backtracking-warning* nil)
  960.  
  961. ;; this is called to print a warning message when the mvine-enforce-cn fn
  962. ;; backtracks because cn cannot be extended into a complete mvine.
  963. ;; This message can be prevented by setting *sky-blue-backtracking-warning*
  964. ;; to nil.
  965. (defun signal-backtracking (cn)
  966.   (when *sky-blue-backtracking-warning*
  967.     (format t "~&Sky-blue: backtracking at ~S~%" cn)))
  968.  
  969. ;; a method is only possible if both: (1) all its outputs are unmarked
  970. ;; (i.e. they aren't being used yet in the mvine) (2) every output
  971. ;; walkstrength is weaker than the cn's strength (except for vars that are
  972. ;; current outputs)
  973. (defun possible-method (mt root-strength mark current-outputs)
  974.   (loop for var in (MT-outputs mt) never
  975.     (or
  976.      ;; if an output var is marked, we can't use this method
  977.      (eql mark (VAR-mark var))
  978.      ;; if an output var is too strong, and is not currently
  979.      ;; determined by the cn, we can't use this method
  980.      (and (not (weaker (VAR-walk-strength var) root-strength))
  981.           (not (member var current-outputs)))
  982.      )
  983.     ))
  984.  
  985. ;; ***** propagating walkabout strengths *****
  986.  
  987. ;; propagate walkstrengths downstream from the given cns and vars.  Cycles
  988. ;; are broken by inserting the most conservative walkstrength (weakest).
  989.  
  990. (defvar *propagate-walkstrength-stack* (sb-stack-create 100))
  991.  
  992. (defun propagate-walkstrength (roots)
  993.   (let* ((prop-mark (new-mark))
  994.      cn)
  995.     ;; mark all cns we will be processing, and collect ordered pplan
  996.     (sb-stack-clear *propagate-walkstrength-stack*)
  997.     (pplan-add *propagate-walkstrength-stack* roots prop-mark)
  998.     ;; scan through pplan
  999.     (loop until (sb-stack-empty *propagate-walkstrength-stack*) do
  1000.       (setq cn (sb-stack-pop *propagate-walkstrength-stack*))
  1001.       (when (eql (CN-mark cn) prop-mark)
  1002.         (cond ((any-immediate-upstream-cns-marked cn prop-mark)
  1003.            ;; Some of this cn's upstream cns have not been processed: there
  1004.            ;; must be a cycle.  Handle it, possibly unmarking other cns in
  1005.            ;; the cycle, and calculating their walkstrengths.
  1006.            (propagate-walkstrength-cycle cn prop-mark)
  1007.            )
  1008.           (t
  1009.            ;; cn is not in a cycle: compute walkstrengths and mark it done
  1010.            (do-selected-method-output-vars (var cn)
  1011.              (setf (VAR-walk-strength var) (compute-walkabout cn var)))
  1012.            (setf (CN-mark cn) nil)
  1013.            ))
  1014.         ))
  1015.     ))
  1016.  
  1017. ;; cn is in a cycle: break the cycle by setting any upstream
  1018. ;; vars determined by the unprocessed cns to have :weakest
  1019. ;; walkabout strength.  (the most conservative choice)
  1020. (defun propagate-walkstrength-cycle (cn prop-mark)
  1021.   (do-selected-method-input-vars (var cn)
  1022.     (let ((upstream-cn (VAR-determined-by var)))
  1023.       (when (and upstream-cn
  1024.          (eql prop-mark (CN-mark upstream-cn)))
  1025.     (setf (VAR-walk-strength var) *weakest-strength*))))
  1026.   ;; compute walkstrengths for cn, and mark it done
  1027.   (do-selected-method-output-vars (var cn)
  1028.     (setf (VAR-walk-strength var) (compute-walkabout cn var)))
  1029.   (setf (CN-mark cn) nil)
  1030.   )
  1031.  
  1032. ;; any-immediate-upstream-cns-unmarked returns t iff none of the cns
  1033. ;; determining the inputs of cn are marked with the given mark
  1034. (defun any-immediate-upstream-cns-marked (cn mark)
  1035.   (do-selected-method-input-vars (var cn)
  1036.     (let ((upstream-cn (VAR-determined-by var)))
  1037.       (when (and upstream-cn
  1038.          (eql mark (CN-mark upstream-cn)))
  1039.     (return-from any-immediate-upstream-cns-marked t))
  1040.       ))
  1041.   ;; none of the cns are marked: return nil
  1042.   nil)
  1043.  
  1044.  
  1045. ;; compute-walkabout calculates the walkabout strength of the variable var
  1046. ;; which is currently a selected output variable of the constraint cn.
  1047. ;; This value is a lower bound on the strength a cn would need to have to
  1048. ;; set this variable (causing this cn to change its selected mt).  Note:
  1049. ;; different output vars may have different walkstrengths, since the cn may
  1050. ;; have different sets of possible mts that don't set each var.  Note: have
  1051. ;; to handle the case where some method's output vars is a subset of other
  1052. ;; method's output vars.  Normally, one wouldn't define such a cn, but it
  1053. ;; is possible to get this in Multi-Garnet with indirect var paths.
  1054. (defun compute-walkabout (cn var)
  1055.   (let* ((min-strength (CN-strength cn))
  1056.          (selected-method (CN-selected-method cn))
  1057.          (selected-out-vars (MT-outputs selected-method)))
  1058.     (loop for mt in (CN-methods cn)
  1059.           unless (eql mt selected-method)
  1060.           do
  1061.           (let ((out-vars (MT-outputs mt))
  1062.                 (max-strength *weakest-strength*))
  1063.             (when (not (member var out-vars))
  1064.               ;; mt doesn't output to var, so this is a possible alternative
  1065.               ;; mt for this cn.  Find max output var walkstrength for this
  1066.               ;; mt, ignoring vars set by currently selected mt
  1067.               (loop for out-var in out-vars
  1068.           when (and (weaker max-strength (VAR-walk-strength out-var))
  1069.                 (not (member out-var selected-out-vars)))
  1070.           do (setf max-strength (VAR-walk-strength out-var)))
  1071.               ;; note: final max-strength will be :weakest if there is a mt
  1072.               ;; with outputs that are a subset of the selected method
  1073.               (when (weaker max-strength min-strength)
  1074.                 (setf min-strength max-strength)))
  1075.             ))
  1076.     min-strength))
  1077.  
  1078. ;; ***** collect unenforced constraints *****
  1079.  
  1080. ;; collect-unenforced traces downstream from all of the vars in
  1081. ;; *redetermined-vars-stack*, adding to *unenforced-cns-stack* any
  1082. ;; unenforced cns that could possibly output to these vars or downstream
  1083. ;; vars.  If collect-equal-p is nil, this only collects cns strictly weaker
  1084. ;; than collection-strength.  If collect-equal-p is non-nil, this collects
  1085. ;; cns weaker than or with the same strength as collection-strength.
  1086. (defun collect-unenforced (collection-strength collect-equal-p)
  1087.   (let ((done-mark (new-mark)))
  1088.     (do-sb-stack-elts (var *redetermined-vars-stack*)
  1089.       (collect-unenforced-mark var collection-strength collect-equal-p done-mark))
  1090.     ))
  1091.  
  1092. (defun collect-unenforced-mark (var collection-strength collect-equal-p done-mark)
  1093.   (loop for cn in (VAR-constraints var)
  1094.       unless (or
  1095.           ;; if cn determines var, ignore
  1096.           (eql cn (VAR-determined-by var))
  1097.           ;; if we've already processed this cn, ignore it
  1098.           (eql done-mark (CN-mark cn))
  1099.           )
  1100.       do
  1101.     ;; we will process this cn now: mark it
  1102.     (setf (CN-mark cn) done-mark)
  1103.     (cond ((enforced cn)
  1104.            ;; cn is an enforced cn that consumes var:
  1105.            ;; collect cns downstream of cn's outputs
  1106.            (do-selected-method-output-vars (out-var cn)
  1107.          (collect-unenforced-mark out-var collection-strength
  1108.                       collect-equal-p done-mark))
  1109.            )
  1110.           ((or (weaker (CN-strength cn) collection-strength)
  1111.            (and collect-equal-p (eql (CN-strength cn) collection-strength)))
  1112.            ;; cn is an unenforced cn that is weak enough to collect
  1113.            (sb-cns-set-add *unenforced-cns-stack* cn)
  1114.            ))
  1115.     ))
  1116.  
  1117. ;; ***** executing methods *****
  1118.  
  1119. (defvar *exec-pplan-stack* (sb-stack-create 100))
  1120.  
  1121. ;; this fn takes the newly-undetermined vars and newly-added cns on
  1122. ;; *exec-roots-stack* and tries to execute methods to enforce the cns in
  1123. ;; the method graph.  if there are no cycles, this will validate all of
  1124. ;; the vars.
  1125. (defun exec-from-roots ()
  1126.   (let* ((prop-mark (new-mark))
  1127.      cn)
  1128.     ;; mark all cns we will be processing, and collect ordered pplan
  1129.     (sb-stack-clear *exec-pplan-stack*)
  1130.     (do-sb-stack-elts (elt *exec-roots-stack*)
  1131.       (cond ((sb-constraint-p elt)
  1132.          (pplan-add *exec-pplan-stack* elt prop-mark))
  1133.         ((and (sb-variable-p elt)
  1134.           (null (VAR-determined-by elt))
  1135.           (not (VAR-valid elt)))
  1136.          ;; only need to exec-from-root of var if it is an undetermined
  1137.          ;; var being changed from non-valid to valid
  1138.          (pplan-add *exec-pplan-stack* elt prop-mark)
  1139.          ;; validate all undetermined vars
  1140.          (setf (VAR-valid elt) t)
  1141.          ))
  1142.       )
  1143.     ;; scan through pplan
  1144.     (loop until (sb-stack-empty *exec-pplan-stack*) do
  1145.       (setq cn (sb-stack-pop *exec-pplan-stack*))
  1146.       (cond ((not (eql prop-mark (CN-mark cn)))
  1147.          ;; this cn has already been processed: ignore
  1148.          nil)
  1149.         ((any-immediate-upstream-cns-marked cn prop-mark)
  1150.          ;; Some of this cn's upstream cns have not been processed:
  1151.          ;; there must be a cycle.  Call fn to handle cycle: this
  1152.          ;; fn may mark other cns as done.
  1153.          (exec-from-cycle cn prop-mark)
  1154.          )
  1155.         (t
  1156.          ;; All of this cn's upstream cns have been processed, so we
  1157.          ;; can now process this one and mark it done
  1158.          (execute-propagate-valid cn)
  1159.          (setf (CN-mark cn) nil)
  1160.          )
  1161.         ))
  1162.     ))
  1163.  
  1164. ;; executes the selected method of cn if all of its inputs are valid.  In
  1165. ;; any case, it propagate the valid flag to the outputs.
  1166. (defun execute-propagate-valid (cn)
  1167.   (let ((inputs-valid (block valid-block
  1168.             (do-selected-method-input-vars (var cn)
  1169.               (when (not (VAR-valid var))
  1170.                 (return-from valid-block nil)))
  1171.             t)))
  1172.     (when inputs-valid
  1173.       (execute-selected-method cn))
  1174.     (do-selected-method-output-vars (var cn)
  1175.       (setf (VAR-valid var) inputs-valid))
  1176.     ))
  1177.  
  1178. (defun execute-selected-method (cn)
  1179.   (funcall (MT-code (CN-selected-method cn)) cn))
  1180.  
  1181. (defvar *sky-blue-cycle-solver-fns* nil)
  1182.  
  1183. ;; handle cycle by trying a series of cycle solvers.  If one of the solvers
  1184. ;; can find a solution, install it in the cycle variables.  If none of the
  1185. ;; solvers can find a solution, invalidate the output vars of all cns in
  1186. ;; the cycle (and downstream of it).
  1187. (defun exec-from-cycle (cn prop-mark)
  1188.   (let* ((cycle-cns (collect-cns-in-cycle (list cn) nil prop-mark)))
  1189.     ;; if any of the cycle input vars (input vars to any of
  1190.     ;; the cns in the cycle that are not set by other cycle cns)
  1191.     ;; are invalid, return without trying to solve the cycle.
  1192.     (loop for cn in cycle-cns do
  1193.       (do-selected-method-input-vars (var cn)
  1194.         (when (and (not (VAR-valid var))
  1195.                (not (member (VAR-determined-by var) cycle-cns)))
  1196.           ;; mark cn and downstream cns as done, and all outputs invalid
  1197.           (unmark-invalidate-downstream cn prop-mark)
  1198.           ;; and return without trying to solve cycle
  1199.           (return-from exec-from-cycle nil))
  1200.         ))
  1201.    ;; print warning
  1202.    (signal-cycle cycle-cns)
  1203.    ;; try cycle solvers
  1204.    (loop for solver-fn in *sky-blue-cycle-solver-fns*
  1205.        when
  1206.      ;; Call solver-fn to try solving cycle.  If it can solve the
  1207.      ;; cycle, it must set all of the var values of vars set by cycle
  1208.      ;; cns, and return t.  If it cannot solve the cycle, it must not
  1209.      ;; change anything, and return nil.
  1210.      (funcall solver-fn cycle-cns)
  1211.        do
  1212.      ;; This solver fn has succeeded.  Clear marks in cycle cns, so we
  1213.      ;; won't process them, and set var-valid for cn outputs
  1214.      (loop for cn in cycle-cns do
  1215.            (setf (CN-mark cn) nil)
  1216.            (do-selected-method-output-vars (var cn)
  1217.          (setf (VAR-valid var) t)))
  1218.      ;; We don't need to try any more cycle solvers
  1219.      (return-from exec-from-cycle nil))
  1220.    ;; None of the cycle solvers were sucessful.  Mark cn and
  1221.    ;; downstream cns as done, and all outputs invalid
  1222.    (unmark-invalidate-downstream cn prop-mark)
  1223.    ))
  1224.  
  1225. ;; return a list of all cns upstream of the cns in roots that have not been
  1226. ;; processed (i.e., cn-mark is not equal to prop-mark).  When called with
  1227. ;; the cycle cn found in exec-from-cycle, this returns all of the cns in
  1228. ;; the cycle.
  1229. (defun collect-cns-in-cycle (roots collected prop-mark)
  1230.   (let* ((cn (car roots))
  1231.      (next-roots (cdr roots)))
  1232.     (cond ((null roots) collected)
  1233.       ((not (equal prop-mark (CN-mark cn)))
  1234.        (collect-cns-in-cycle next-roots collected prop-mark))
  1235.       ((member cn collected)
  1236.        (collect-cns-in-cycle next-roots collected prop-mark))
  1237.       (t
  1238.        (do-selected-method-input-vars (var cn)
  1239.          (when (VAR-determined-by var)
  1240.            (push (VAR-determined-by var) next-roots)))
  1241.        (collect-cns-in-cycle
  1242.         next-roots (cons cn collected) prop-mark)
  1243.        ))
  1244.     ))
  1245.  
  1246. (defvar *sky-blue-cycle-warning* nil)
  1247.  
  1248. (defun signal-cycle (cns)
  1249.   (when *sky-blue-cycle-warning*
  1250.     (let* ((*print-length* 5))
  1251.       (declare (special *print-length*))
  1252.       (format t "~&Sky-blue cycle: ~S~%" cns))
  1253.     ))
  1254.  
  1255. (defun linear-eqn-cycle-solver (cns)
  1256.   (let* ((cycle-vars (loop for cn in cns
  1257.              append (selected-method-output-vars cn)))
  1258.      (eqns (loop for cn in cns collect
  1259.              (let* ((eqn (extract-cn-linear-eqn cn cycle-vars)))
  1260.                ;; if we can't extract a linear equation from one of
  1261.                ;; the cns, we can't solve the cycle with this cycle
  1262.                ;; solver: return nil immediately
  1263.                (when (null eqn)
  1264.              (return-from linear-eqn-cycle-solver nil))
  1265.                eqn)))
  1266.      (soln (solve-linear-eqns eqns))
  1267.      )
  1268.     (cond (soln
  1269.        ;; we have a soln: install calculated values in vars and return t
  1270.        (loop for var in cycle-vars do
  1271.          (setf (VAR-value var)
  1272.            (linear-eqn-soln-val soln var)))
  1273.        t)
  1274.       (t
  1275.        ;; no solution found: return nil
  1276.        nil))
  1277.     ))
  1278.  
  1279. ;; takes a list of enforced cns, and unmarks all downstream enforced cns
  1280. ;; that are marked with prop-mark (stopping the recursion when unmarked cns
  1281. ;; are found).  All vars that are outputs of these cns are marked invalid.
  1282. (defun unmark-invalidate-downstream (cn prop-mark)
  1283.   (when (eql prop-mark (CN-mark cn))
  1284.     (setf (CN-mark cn) nil)
  1285.     (do-selected-method-output-vars (var cn)
  1286.       (setf (VAR-valid var) nil)
  1287.       (do-consuming-constraints (downstream-cn var)
  1288.     (unmark-invalidate-downstream downstream-cn prop-mark))
  1289.       )))
  1290.  
  1291. ;; ***** constructing propagation plans *****
  1292.  
  1293. ;; given a cn, pplan-add recursively travels downstream of the cn, marking
  1294. ;; all cns with the given mark, and adds all marked cns to the specified
  1295. ;; stack.  When this is done, the stack contains, in order the cns that
  1296. ;; will have to be examined to propagate walkstrengths or var values.  Each
  1297. ;; cn will only appear at most once on the stack (since they are marked
  1298. ;; when they are added).  Note that it will be necessary to check for
  1299. ;; cycles while examining the cns.  Note: further cns can be added as roots
  1300. ;; of the propagation, simply by calling pplan-add again.  pplan will also
  1301. ;; take vars, or lists and stacks of cns and vars.
  1302.  
  1303. (defun pplan-add (stack obj done-mark)
  1304.   (cond ((sb-constraint-p obj)
  1305.      (when (and (enforced obj)
  1306.             (not (eql done-mark (CN-mark obj))))
  1307.        ;; process unmarked, enforced constraint by marking it, collecting
  1308.        ;; downstream constraints, and pushing it on top of the pplan stack.
  1309.        (setf (CN-mark obj) done-mark)
  1310.        (do-selected-method-output-vars (out-var obj)
  1311.          (pplan-add stack out-var done-mark))
  1312.        (sb-stack-push stack obj))
  1313.      )
  1314.     ((sb-variable-p obj)
  1315.      ;; process variable by collecting downstream constraints rooted with
  1316.      ;; constraints directly consuming the variable
  1317.      (do-consuming-constraints (cn obj)
  1318.        (pplan-add stack cn done-mark))
  1319.      )
  1320.     ;; accept list of cns and vars
  1321.     ((null obj)
  1322.      nil)
  1323.     ((listp obj)
  1324.      (pplan-add stack (car obj) done-mark)
  1325.      (pplan-add stack (cdr obj) done-mark))
  1326.     ;; also accept stack of cns and vars
  1327.     ((sb-stack-p obj)
  1328.      (do-sb-stack-elts (elt obj)
  1329.        (pplan-add stack elt done-mark)))
  1330.     (t
  1331.      (cerror "cont" "pplan-add: bad object ~S" obj))
  1332.     ))
  1333.  
  1334. ;; ***** extracting and executing plans *****
  1335.  
  1336. (defvar *extract-plan-stack* (sb-stack-create 100))
  1337.  
  1338. (defun extract-plan (root-cns)
  1339.   (let ((prop-mark (new-mark))
  1340.     (good-cns nil)
  1341.     (bad-cns nil)
  1342.     cn)
  1343.     ;; mark all cns we will be processing, and collect ordered pplan
  1344.     (sb-stack-clear *extract-plan-stack*)
  1345.     (pplan-add *extract-plan-stack* root-cns prop-mark)
  1346.     ;; scan through pplan
  1347.     (loop until (sb-stack-empty *extract-plan-stack*) do
  1348.       (setq cn (sb-stack-pop *extract-plan-stack*))
  1349.       (cond ((not (eql prop-mark (CN-mark cn)))
  1350.          ;; this cn has already been processed: ignore
  1351.          nil)
  1352.         ((any-immediate-upstream-cns-marked cn prop-mark) 
  1353.          ;; Some of this cn's upstream cns have not been processed:
  1354.          ;; there must be a cycle.  Add cn to invalid cns list.
  1355.          (push cn bad-cns)
  1356.          ;; note: do _not_ unmark this cn: all cns
  1357.          ;; in the cycle, and downstream of it, will be added
  1358.          ;; to the bad list.
  1359.          )
  1360.         (t
  1361.          ;; all the upstream cns have been processed, so unmark this one
  1362.          ;; and add it to the beginning of the plan
  1363.          ;; (will reverse plan before returning)
  1364.          (setf (CN-mark cn) nil)
  1365.          (push cn good-cns)
  1366.          )))
  1367.     (create-valid-plan root-cns (nreverse good-cns) bad-cns)
  1368.     ))
  1369.  
  1370. ;; a (plan-good-cns plan) is just a list of constraints, to be executed in
  1371. ;; order
  1372. (defun execute-plan (plan)
  1373.   (cond ((sb-plan-valid plan)
  1374.      (loop for cn in (sb-plan-good-cns plan) do
  1375.            (execute-propagate-valid cn))
  1376.      )
  1377.     (t
  1378.      (cerror "noop" "trying to execute invalid plan ~S" plan))
  1379.     ))
  1380.  
  1381. ;; ** plan invalidation **
  1382.  
  1383. (defun create-valid-plan (root-cns good-cns bad-cns)
  1384.   (let ((plan (make-sb-plan :root-cns root-cns
  1385.                 :good-cns good-cns
  1386.                 :bad-cns bad-cns
  1387.                 :valid t)))
  1388.     (add-valid-plan-to-cns plan (sb-plan-good-cns plan))
  1389.     (add-valid-plan-to-cns plan (sb-plan-bad-cns plan))
  1390.     (add-valid-plan-to-cns plan (sb-plan-root-cns plan))
  1391.     plan))
  1392.  
  1393. (defun add-valid-plan-to-cns (plan cns)
  1394.   (loop for cn in cns
  1395.       do (set-sb-slot cn :valid-plans
  1396.               (adjoin plan (get-sb-slot cn :valid-plans)))))
  1397.  
  1398. (defun invalidate-plans-on-setting-method (cn new-mt)
  1399.   (invalidate-constraint-plans cn)
  1400.   (when new-mt
  1401.     (do-method-input-vars (var cn new-mt)
  1402.       (let ((input-cn (VAR-determined-by var)))
  1403.     (when input-cn
  1404.       (invalidate-constraint-plans input-cn))
  1405.     )))
  1406.   )
  1407.   
  1408. (defun invalidate-constraint-plans (invalid-cn)
  1409.   (let* ()
  1410.     (loop for plan in (get-sb-slot invalid-cn :valid-plans) do
  1411.       ;; (when (sb-plan-valid plan) (format t "~&invalidating plan ~S~%" plan))
  1412.       (setf (sb-plan-valid plan) nil)
  1413.       (remove-invalid-plan-from-other-cns plan (sb-plan-good-cns plan) invalid-cn)
  1414.       (remove-invalid-plan-from-other-cns plan (sb-plan-bad-cns plan) invalid-cn)
  1415.       (remove-invalid-plan-from-other-cns plan (sb-plan-root-cns plan) invalid-cn)
  1416.       )
  1417.     (set-sb-slot invalid-cn :valid-plans nil)
  1418.     ))
  1419.  
  1420. (defun remove-invalid-plan-from-other-cns (plan cns invalid-cn)
  1421.   (loop for cn in cns do
  1422.     (when (not (eql cn invalid-cn))
  1423.       (set-sb-slot cn :valid-plans
  1424.                (remove plan (get-sb-slot cn :valid-plans)))
  1425.       )))
  1426.